<?php

namespace App\Models\Trip\TripOrderCosts\Repositories;

use App\Models\Orders\Repositories\Interfaces\OrdersInterface;
use App\Models\Passengers\Repositories\Interfaces\OrderPassengerInterface;
use App\Models\Train\TrainOrderPassengers\TrainOrderPassenger;
use App\Models\Trip\TripOrderCosts\Repositories\Interfaces\TripOrderPassengerCostsRepositoryInterface;
use App\Models\Trip\TripOrderCosts\TripOrderCost;
use App\Models\Trip\TripOrderCosts\TripOrderPassengerCost;
use App\Trip\Repository\BaseRepository;
use Carbon\Carbon;
use Exception;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;

class TripOrderPassengerCostsRepository extends BaseRepository implements TripOrderPassengerCostsRepositoryInterface
{

    public function __construct(TripOrderPassengerCost $model)
    {
        parent::__construct($model);
    }

    /**
     * @throws Exception
     */
    public function addMore($costs)
    {
        $validator = Validator::make($costs, [
            "*.user_id"      => "required",
            '*.trip_id'      => "required",
            '*.trip_type'    => "required",
            '*.order_sn'     => "required",
            '*.passenger_id' => "required",
            '*.sequence'     => "required",
            '*.type'         => "required",
            '*.parent_type'  => "required",
            '*.price'        => "required",
            '*.name'         => "required",
        ]);

        if ($validator->fails()) {
            Log::error(json_encode([
                "成本明细添加失败",
                $validator->errors()->first(),
                $costs,
            ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
            throw new Exception("参数错误");
        }
        $created_at = Carbon::now()->toDateTimeString();
        $costs      = collect($costs)->map(function ($detail) use ($created_at) {
            if ($detail['type'] == TripOrderCost::COST_TYPE_SNAP_EDIT_TICKET_PRICE_DIFF) {
                $detail['parent_type'] = TripOrderCost::COST_TYPE_TICKET;
            }
            $detail['created_at'] = $created_at;
            $detail['updated_at'] = $created_at;
            return $detail;
        })->toArray();

        return $this->model->insert($costs);
    }

    /**
     * @throws Exception
     */
    public function addPassengerSelectSeatCost(OrderPassengerInterface $passenger, array $cost): TripOrderPassengerCost
    {
        if ($passenger_selected_cost = $this->getOrderPassengerSelectSeatCost($passenger)) {
            return $passenger_selected_cost;
        }
        return $this->addOne($passenger, $cost);
    }

    /**
     * 获取乘客选座 成本
     *
     * @param TrainOrderPassenger $passenger
     *
     * @return TripOrderPassengerCost|null
     * @throws Exception
     */
    public function getOrderPassengerSelectSeatCost(OrderPassengerInterface $passenger): ?TripOrderPassengerCost
    {
        return $this->findOneByPassenger($passenger, TripOrderCost::COST_TYPE_SELECT_SEAT);
    }

    /**
     * @throws Exception
     */
    public function findOneByPassenger(OrderPassengerInterface $passenger, int $type, string $name = '', string $pay_sn = ''): ?TripOrderPassengerCost
    {
        $where = [
            'user_id'      => $passenger->getUserId(),
            'order_sn'     => $passenger->getOrderSn(),
            "passenger_id" => $passenger->getPassengerId(),
            "sequence"     => $passenger->getSequence(),
            "type"         => $type,
        ];

        if (TripOrderCost::mayHasMoreRecord($type)) {
            if (!$pay_sn) {
                throw new Exception("类型 {$type} 缺少参数,pay_sn");
            }
            $where['pay_sn'] = $pay_sn;
        }

        if ($name) {
            $where['name'] = $name;
        }
        return $this->findOneBy($where);
    }

    /**
     * @throws Exception
     */
    public function addOne(OrderPassengerInterface $passenger, array $data): TripOrderPassengerCost
    {
        $pay_sn = $data['pay_sn'] ?? '';
        if ($cost_info = $this->findOneByPassenger($passenger, $data['type'], $data['name'], $pay_sn)) {
            // 可能涉及到更新
            if (!$cost_info->pay_sn && $pay_sn) {
                $this->update(['pay_sn' => $pay_sn], $cost_info);
            }
            return $cost_info;
        }

        $order_info           = $passenger->getOrderInfo();
        $data['user_id']      = $passenger->getUserId();
        $data['order_sn']     = $passenger->getOrderSn();
        $data['trip_id']      = $order_info->getTripId();
        $data['trip_type']    = $order_info->getTripType();
        $data['passenger_id'] = $passenger->getPassengerId();
        $data['sequence']     = $passenger->getSequence();

        $validator = Validator::make($data, [
            "user_id"      => "required",
            'trip_id'      => "required",
            'trip_type'    => "required",
            'order_sn'     => "required",
            'passenger_id' => "required",
            'sequence'     => "required",
            'type'         => "required",
            'parent_type'  => "required",
            'price'        => "required",
            'name'         => "required",
        ]);

        if ($validator->fails()) {
            throw new Exception("参数错误");
        }

        return $this->create($data);

    }

    /**
     * @throws Exception
     */
    public function addByNewOrderPassengerTicketCost(OrderPassengerInterface $passenger, array $cost): bool
    {
        // 未支付的不需要更新
        $pay_sn   = $cost['pay_sn'] ?? '';
        $new_type = $cost['type'] ?? '';
        if (!$pay_sn) {
            return true;
        }
        $before_passenger_costs  = $this->listOrderPassengerTicketCosts($passenger);
        $before_order_cost_price = $before_passenger_costs->sum(fn($detail) => $detail['price']);
        $new_price               = $cost['new_price'];
        // 如果价格没变直接跳过
        if ($before_order_cost_price == $new_price) {
            return true;
        }

        $price = $new_price - $before_order_cost_price;
        // 已新增的编辑差价记录
        if ($new_type == TripOrderCost::COST_TYPE_SNAP_EDIT_TICKET_PRICE_DIFF) {
            $this->addOne($passenger, [
                "parent_type" => TripOrderCost::COST_TYPE_TICKET,
                "type"        => $new_type,
                "name"        => TripOrderCost::COST_TYPE_DESC[$new_type],
                "price"       => $price, // 单价
                "pay_sn"      => $pay_sn,
            ]);
            return true;
        } else {
            throw new Exception("不支持的新增, new_type: {$new_type},{$pay_sn}");
        }
    }

    /**
     * 列出乘客票价相关的明细
     * @param OrderPassengerInterface $passenger
     * @return Collection
     */
    public function listOrderPassengerTicketCosts(OrderPassengerInterface $passenger): Collection
    {
        $condition = [
            'parent_type' => TripOrderCost::COST_TYPE_TICKET, // type in COST_TYPE_TICKET  or COST_TYPE_SNAP_EDIT_TICKET_PRICE_DIFF
        ];
        return $this->listByOrderPassengers($passenger, $condition);
    }

    public function listByOrderPassengers(OrderPassengerInterface $passenger, array $condition = []): Collection
    {
        $where = [
            'user_id'      => $passenger->getUserId(),
            'passenger_id' => $passenger->getPassengerId(),
            'sequence'     => $passenger->getSequence(),
            'order_sn'     => $passenger->getOrderSn(),
        ];
        if (!empty($condition)) {
            $where = array_merge($where, $condition);
        }

        return $this->findBy($where);
    }

    public function updateOne(TripOrderPassengerCost $cost, array $data): bool
    {
        return $this->update($data, $cost);
    }

    public function updatePaySnByOrder(OrdersInterface $order, string $pay_sn, array $types = []): bool
    {
        $where = [
            'order_sn'  => $order->getOrderSn(),
            'trip_id'   => $order->getTripId(),
            'trip_type' => $order->getTripType(),
            'user_id'   => $order->getUserId(),
        ];
        return $this->where($where)
                    ->where('pay_sn', '')
                    ->when($types, function ($q) use ($types) {
                        $q->whereIn('type', $types);
                    })
                    ->update([
                        'pay_sn' => $pay_sn,
                    ]);
    }

    public function findOneOrderPassengerTicketCost(OrderPassengerInterface $passenger, string $pay_sn): ?TripOrderPassengerCost
    {
        $where = [
            'user_id'      => $passenger->getUserId(),
            'passenger_id' => $passenger->getPassengerId(),
            'sequence'     => $passenger->getSequence(),
            'order_sn'     => $passenger->getOrderSn(),
            'pay_sn'       => $pay_sn,
        ];
        return $this->findOneBy($where);
    }
}